package com.mk.seckill.controller;

import com.mk.seckill.pojo.User;
import com.mk.seckill.service.IGoodsService;
import com.mk.seckill.service.IUserService;
import com.mk.seckill.vo.DetailVo;
import com.mk.seckill.vo.GoodsVo;
import com.mk.seckill.vo.RespBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("/goods")
public class GoodsController {
	/**
	 * @Author hhwu
	 * @Description //TODO 商品相关的请求
	 * @Date 13:51 2022/6/7
	 **/
	
	@Autowired
	private IUserService userService;
	@Autowired
	private IGoodsService goodsService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private ThymeleafViewResolver thymeleafViewResolver;// 用来手动渲染

	@RequestMapping(value = "/toList", produces = "text/html;charset=utf-8")
	@ResponseBody
	public String toList(Model model, User user,// user并不是前端传来的，而是WebConfig中生成的，可以直接在controller调用
						 HttpServletRequest request, HttpServletResponse response/*, HttpSession session, @CookieValue("userTicket") String ticket*/) {
		/**
		 * @Author hhwu
		 * @Description //TODO 准备好商品列表数据，跳转到商品列表页。优化后将手动渲染商品列页面，然后将页面传入redis缓存，以后每次放问该页面时，都优先从redis中取
		 * TODO 该接口在Windows优化前的压力测试qps：1332
		 * TODO 使用页面缓存后的压力测试qps：2342
		 * @Date 10:34 2022/6/7
		 * @Param [model, user, request, response]
		 * @return java.lang.String
		 **/
//		// 未使用redis缓存ticket时的判断用户登录状态的方法
//		// 使用redis缓存ticket时，可以直接通过配置MVC配置类WebConfig，来处理对ticket凭证验证用户存在的判断
//		if (StringUtils.isEmpty(ticket)) {
//			return "login";
//		}
////		User user = (User) session.getAttribute(ticket);
//		User user = userService.getUserByCookie(ticket, request, response);// 通过cookie中的ticket凭证从redis中获取对应的user
//		if (null == user) {
//			return "login";
//		}

		// 先尝试从Redis缓存中获取页面，如果不为空，直接返回页面
		ValueOperations valueOperations = redisTemplate.opsForValue();
		String html = (String) valueOperations.get("goodsList");// goodsList.html页面在redis中的key为goodsList
		if (!StringUtils.isEmpty(html)) {// 如果缓存中有，直接返回
			return html;
		}

		model.addAttribute("user", user);
		model.addAttribute("goodsList", goodsService.findGoodsVo());
//		return "goodsList";// 直接返回模版进行自动渲染

		//如果redis中没有该页面，手动渲染，存入Redis并返回
		WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale(),// 手动渲染，将model中的数据转为map
				model.asMap());
		html = thymeleafViewResolver.getTemplateEngine().process("goodsList", context);// 获得渲染结果，数据塞入模版
		if (!StringUtils.isEmpty(html)) {
			valueOperations.set("goodsList", html, 60, TimeUnit.SECONDS);// 渲染后的页面存入redis缓存，设置60s过期
		}
		return html;
	}

	@RequestMapping(value = "/detail/{goodsId}", produces = "text/html;charset=utf-8")
	@ResponseBody
	public String detail(Model model, User user, @PathVariable Long goodsId, HttpServletRequest request, HttpServletResponse response) {
		/**
		 * @Author hhwu
		 * @Description //TODO 商品详情页数据准备，跳转到商品详情页，toDetail方法页面静态化优化前、redis优化后的版本。引入页面静态化后，该方法被废弃
		 * @Date 16:01 2022/6/7
		 * @Param [user, goodsId]
		 * @return com.mk.seckill.vo.RespBean
		 **/
		ValueOperations valueOperations = redisTemplate.opsForValue();
		String html = (String) valueOperations.get("goodsDetail:" + goodsId);// 因为请求路径不同导致返回的页面不同，所以需要用不同的key存对应的页面
		if (!StringUtils.isEmpty(html)) {// 如果缓存中有，直接返回
			return html;
		}

		//goodsVo同时具有普通商品属性和秒杀商品属性
		GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);
		Date startDate = goodsVo.getStartDate();
		Date endDate = goodsVo.getEndDate();
		Date nowDate = new Date();
		//秒杀状态
		int seckillStatus = 0;
//		//秒杀倒计时
		int remainSeconds = 0;

		if (nowDate.before(startDate)) {//秒杀还未开始
			seckillStatus = 0;
			remainSeconds = ((int) ((startDate.getTime() - nowDate.getTime()) / 1000));// 单位：s
		} else if (nowDate.after(endDate)) {//	秒杀已结束
			seckillStatus = 2;
			remainSeconds = -1;
		} else {//秒杀中
			seckillStatus = 1;
			remainSeconds = 0;
		}

		model.addAttribute("user", user);
		model.addAttribute("goods", goodsVo);
		model.addAttribute("seckillStatus", seckillStatus);
		model.addAttribute("remainSeconds", remainSeconds);
//		return "goodsDetail";

		//如果redis中没有该页面，手动渲染，存入Redis并返回
		WebContext context = new WebContext(request, response, request.getServletContext(), request.getLocale(),// 手动渲染，将model中的数据转为map后
				model.asMap());
		html = thymeleafViewResolver.getTemplateEngine().process("goodsDetail", context);// 获得渲染结果，数据塞入模版
		if (!StringUtils.isEmpty(html)) {
			valueOperations.set("goodDetail:" + goodsId, html, 60, TimeUnit.SECONDS);// 渲染后的页面存入redis缓存，设置60s过期
		}
		return html;
	}

	@RequestMapping(value = "/toDetail/{goodsId}", method = RequestMethod.GET)
	@ResponseBody
	public RespBean toDetail(User user, @PathVariable Long goodsId) {
		/**
		 * @Author hhwu
		 * @Description //TODO 商品详情页数据准备，toDetail页面静态化优化后的版本。放弃在服务端的redis中缓存整个页面的方式，静态界面缓存在前端，这里仅返回detailVo对象数据。
		 * @Date 16:01 2022/6/7
		 * @Param [user, goodsId]
		 * @return com.mk.seckill.vo.RespBean
		 **/
		//goodsVo同时具有普通商品属性和秒杀商品属性
		GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);
		Date startDate = goodsVo.getStartDate();
		Date endDate = goodsVo.getEndDate();
		Date nowDate = new Date();
		//秒杀状态
		int seckillStatus = 0;
//		//秒杀倒计时
		int remainSeconds = 0;

		if (nowDate.before(startDate)) {//秒杀还未开始
			seckillStatus = 0;
			remainSeconds = ((int) ((startDate.getTime() - nowDate.getTime()) / 1000));// 单位：s
		} else if (nowDate.after(endDate)) {//	秒杀已结束
			seckillStatus = 2;
			remainSeconds = -1;
		} else {//秒杀中
			seckillStatus = 1;
			remainSeconds = 0;
		}
		DetailVo detailVo = new DetailVo();
		detailVo.setUser(user);
		detailVo.setGoodsVo(goodsVo);
		detailVo.setRemainSeconds(remainSeconds);
		detailVo.setSeckillStatus(seckillStatus);
		return RespBean.success(detailVo);
	}
}